package org.hxzon.cyclone;

import java.util.ArrayList;
import java.util.List;

import org.hxzon.cyclone.contract.Contact;
import org.hxzon.cyclone.contract.ContactGenerator;
import org.hxzon.cyclone.contract.ContactResolver;

//world.h,world.cpp
public class World {
    /**
     * True if the world should calculate the number of iterations
     * to give the contact resolver at each frame.
     */
    private boolean calculateIterations;

    /**
     * Holds a single rigid body in a linked list of bodies.
     */
    private static class BodyRegistration {
        RigidBody body;
        BodyRegistration next;
    };

    /**
     * Holds the head of the list of registered bodies.
     */
    private BodyRegistration firstBody;//pointer

    /**
     * Holds the resolver for sets of contacts.
     */
    private ContactResolver resolver;

    /**
     * Holds one contact generators in a linked list.
     */
    private static class ContactGenRegistration {
        ContactGenerator gen;
        ContactGenRegistration next;
    }

    /**
     * Holds the head of the list of contact generators.
     */
    private ContactGenRegistration firstContactGen;//pointer

    /**
     * Holds an array of contacts, for filling by the contact
     * generators.
     */
    private List<Contact> contacts;

    /**
     * Creates a new simulator that can handle up to the given
     * number of contacts per frame. You can also optionally give
     * a number of contact-resolution iterations to use. If you
     * don't give a number of iterations, then four times the
     * number of detected contacts will be used for each frame.
     */
    //unsigned,unsigned
    public World(long iterations) {
        firstBody = null;
        resolver = new ContactResolver(iterations);
        firstContactGen = null;
        contacts = new ArrayList<Contact>();
        calculateIterations = (iterations == 0);
    }

    public World() {
        this(0);
    }

    public void destroy() {
        //delete[] contacts;
    }

    /**
     * Calls each of the registered contact generators to report
     * their contacts. Returns the number of generated contacts.
     */
    public int generateContacts() {

        ContactGenRegistration reg = firstContactGen;
        while (reg != null) {
            reg.gen.addContact(contacts);
            reg = reg.next;
        }

        return contacts.size();
    }

    /**
     * Processes all the physics for the world.
     */
    public void runPhysics(double duration) {
        // First apply the force generators
        //registry.updateForces(duration);

        // Then integrate the objects
        BodyRegistration reg = firstBody;
        while (reg != null) {
            // Remove all forces from the accumulator
            reg.body.integrate(duration);

            // Get the next registration
            reg = reg.next;
        }

        // Generate contacts
        int usedContacts = generateContacts();

        // And process them
        if (calculateIterations) {
            resolver.setIterations(usedContacts * 4);
        }
        resolver.resolveContacts(contacts, duration);
    }

    /**
     * Initialises the world for a simulation frame. This clears
     * the force and torque accumulators for bodies in the
     * world. After calling this, the bodies can have their forces
     * and torques for this frame added.
     */
    public void startFrame() {
        BodyRegistration reg = firstBody;
        while (reg != null) {
            // Remove all forces from the accumulator
            reg.body.clearAccumulators();
            reg.body.calculateDerivedData();

            // Get the next registration
            reg = reg.next;
        }
    }
}
